<?php

class DBU_File_System {

	protected $_uploadErrors = array(
		0 => "There is no error, the file uploaded with success",
		1 => "The uploaded file exceeds the upload_max_filesize directive in php.ini",
		2 => "The uploaded file exceeds the MAX_FILE_SIZE directive that was specified in the HTML form",
		3 => "The uploaded file was only partially uploaded",
		4 => "No file was uploaded",
		6 => "Missing a temporary folder"
	);


    /**
     * Returns error message on upload, if any
     *
     * @param string $file
     * @param array $extensions
     * @return mixed
     */
	public function getUploadError($file, $extensions = array()) {
        $messages = array(
            'max_post'      => 'POST exceeded maximum allowed size.',
            'no_upload'     => 'No upload found in \$_FILES',
            'bad_upload'    => 'Upload failed is_uploaded_file test.',
            'no_name'       => 'File has no name.',
            'bad_extension' => 'Invalid file extension',
        );

        $errorCode = $this->getUploadErrorNo($file, $extensions);
        if (is_int($errorCode)) {
            return $this->_uploadErrors[$errorCode];
        } elseif(is_string($errorCode)) {
            return $messages[$errorCode];
        }

        return false;
	}

    /**
     * Returns error message on upload, if any
     *
     * @param string $file
     * @param array $extensions
     * @return mixed
     */
	public function getUploadErrorNo($file, $extensions = array()) {
		$result = false;

        $maxUpload  = ini_get("post_max_size");
		$unit       = strtoupper(substr($maxUpload, -1));
		$multiplier = $unit == 'M' ? 1048576 : ($unit == 'K' ? 1024 : ($unit == 'G' ? 1073741824 : 1));

		if ($maxUpload && ((int) $_SERVER['CONTENT_LENGTH'] > $multiplier * (int) $maxUpload)) {
			$result = "max_post";
		}

		if (!isset($file)) {
			$result = "no_upload";

		} else if (isset($file["error"]) && $file["error"] != 0) {
			$result = $file["error"];

		} else if (!isset($file["tmp_name"]) || !@is_uploaded_file($file["tmp_name"])) {
			$result = "bad_upload";

		} else if (!isset($file['name'])) {
			$result = "no_name";
		}

        if ($extensions && !in_array($this->getExtension($file['name']), $extensions)) {
			$result = "bad_extension";
		}

		return $result;
	}

    /**
     * Gets list of all files within a directory
     *
     * @param string $dir
     * @param boolean $recursive
     * @return array
     */
	public function scanDir($dir, $recursive = false) {
		$result = array();

		if (is_dir($dir)) {
			if ($recursive) {
				$iterator = new RecursiveDirectoryIterator($dir);
				foreach (new RecursiveIteratorIterator($iterator, RecursiveIteratorIterator::CHILD_FIRST) as $file) {                    
					if ($file->isFile()) {
                        $result[] = $file->getFilename();
					}
				}
			} else {
                $iterator = new DirectoryIterator($dir);
                foreach ($iterator as $file) {
                    if ($file->isFile()) {
                         $result[] = $file->getFilename();
                    }
                }
			}
		}

		return $result;
	}


    /**
     * Recursively create a directory and set it's permissions
     * 
     * @param string $dir
     * @param int $mode
     * @return boolean
     */
	public function createDir($dir, $mode = 0777) {
        return is_dir($dir) ? true : mkdir($dir, $mode, true);
	}


    /**
     * Builds array-tree of directory, with files as final nodes
     *
     * @param string $dir
     * @param array $tree
     * @return array
     */
    public function treeDir($dir, $tree = array()) {
        $dir = realpath($dir);
        $d   = dir($dir);
        
        while (false != ($entry = $d->read())) {
            $complete = $d->path."/".$entry;
            if (!in_array($entry, array(".", "..", ".svn"))) {
                if (is_dir($complete)) {
                    $tree[$entry] = $this->treeDir($complete, $tree[$dir][$entry]);
                } else {
                    $tree[] = $entry;
                }
            }
        }

        $d->close();
        return $tree;
    }


    /**
     * Recursively removes a directory
     * 
     * @param string $dir
     */
	public function removeDir($dir) {
        $dir = rtrim($dir, "/");
        
        if (is_dir($dir)) {
            $files = scandir($dir);

            array_shift($files);
            array_shift($files);

            foreach ($files as $file) {
                $file = $dir . '/' . $file;
                if (is_dir($file)) {
                    $this->removeDir($file);
                } else {
                    unlink($file);
                }
            }

            rmdir($dir);
        }
	}


    /**
     * Recursively empties a directory
     * 
     * @param string $dir
     */
	public function emptyDir($dir) {
        $dir = rtrim($dir, "/");

        $files = scandir($dir);

        array_shift($files);
        array_shift($files);

        foreach ($files as $file) {
            $file = $dir . '/' . $file;
            if (is_dir($file)) {
                $this->removeDir($file);
            } else {
                unlink($file);
            }
        }
	}


	public function deleteFile($path) {
		if (file_exists($path)) {
			unlink($path);
		}
	}


    /**
     * Get file extension
     *
     * @param string $str
     * @return string
     */
    public function getExtension($str) {
        return strtolower(pathinfo($str, PATHINFO_EXTENSION));
    }
    

    /**
     * Singleton
     * 
     * @return DBU_File_System
     */
	public static function instance() {
		static $instance;
		if (!($instance instanceof self)) {
			$instance = new self();
		}
		return $instance;
	}
}
